using FreeTypeSharp;
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEditor.PackageManager;
using UnityEngine;
using UnityEngine.XR;

[RequireComponent(typeof(MeshFilter))]
[RequireComponent(typeof(MeshRenderer))]
public class drawtext_harfbuzzz : MonoBehaviour
{
    public TextAsset font;
    public string drawText;


    PackTexture packTexture;
    unsafe FT_LibraryRec_* _ft_lib = null;//ttf library
    unsafe FT_FaceRec_* _ft_face = null;//对应字体的face
    string _text;

    byte[] _ttf;

    List<Vector3> mesh_pos = new List<Vector3>();
    List<Vector2> mesh_uv = new List<Vector2>();
    int mesh_x = 0;
    const int fontsize = 64;







    /// HarfBuzz 增加部分
    /// /////////////////////////////////////////////////////////////////
    HBSharp.HB_Blob hbblob;
    HBSharp.HB_Face hbface;
    HBSharp.HB_Font hbfont;
    // Start is called before the first frame update
    void Start()
    {

    }
    //简洁的Glyph转换函数
    //不能显示特殊字符，问题就出在这个函数上
    unsafe uint[] String2Glyphs(string text)
    {


     
        var hbbuffer = HBSharp.hb_buffer_create();

        fixed (char* ptr = text)
        {
            HBSharp.hb_buffer_add_utf16(hbbuffer, (ushort*)ptr, text.Length, 0, -1);
        }
        //猜测buf内容
        HBSharp.hb_buffer_guess_segment_properties(hbbuffer);

        //阴蒂语增加
        //hb_buffer_set_script(hbbuffer, HBSharp.HB_SCRIPT_DEVANAGARI);
        //var bts = System.Text.Encoding.ASCII.GetBytes("hin");
        //fixed (byte* ptr = bts)
        //{
        //    var lang = hb_language_from_string(ptr, bts.Length);
        //    hb_buffer_set_language(hbbuffer, lang);
        //}

        Debug.LogWarning("==>从字符串创建HBBuffer");

        //整形buf
        HBSharp.hb_shape(hbfont, hbbuffer, IntPtr.Zero, 0);
        Debug.LogWarning("==>整形HbBuffer");


        var len = HBSharp.hb_buffer_get_length(hbbuffer);
        Debug.LogWarning("==>HbBuffer Len=" + len + " textlen=" + text.Length);


        var dir = HBSharp.hb_buffer_get_direction(hbbuffer);
        Debug.LogWarning("==>文字方向=" + dir);


        //取结果
        var infos = HBSharp.hb_buffer_get_glyph_infos(hbbuffer, out var infolen);

        Debug.LogWarning("==>HbBuffer infos=" + (IntPtr)infos + " count=" + infolen);
        var poss = HBSharp.hb_buffer_get_glyph_positions(hbbuffer, out var poslen);
        Debug.LogWarning("==>HbBuffer poss=" + (IntPtr)poss + " count=" + poslen);

        uint[] glyphs = new uint[infolen];

        for(var i=0;i< infolen;i++)
        {
            glyphs[i] = infos[i].codepoint;
        }
        return glyphs;
        //foreach (var c in text)
        //{
        //    var index = FT.FT_Get_Char_Index(_ft_face, (System.UIntPtr)c);
        //    glyphs.Add(index);
        //    Debug.LogWarning(c + "=>" + index);
        //}
        //return glyphs.ToArray();
    }
    // Update is called once per frame
    void Update()
    {
        bool dirty = false;
        if (drawText != _text)
        {

            _text = drawText;
            dirty = true;
            Debug.LogWarning("text dirty");
        }
        if (_ttf == null || font.bytes == null || _ttf.Length != font.bytes.Length)
        {
            _ttf = font.bytes;
            ClearFont();
            dirty = true;
            Debug.LogWarning("font dirty");
        }
        if (dirty)
        {

            UpdateText();
        }

    }

    unsafe void UpdateText()
    {
        ClearMesh();

        if (_ft_lib == null)
        {
            packTexture = new PackTexture();



            FT_LibraryRec_* lib;
            FT.FT_Init_FreeType(&lib);
            _ft_lib = lib;
        }

        if (_ttf == null || _text == null)
        {
            return;
        }

        if (_ft_face == null)
        {
            fixed (byte* ptr = _ttf)
            {
                FT_FaceRec_* face;
                FT.FT_New_Memory_Face(_ft_lib, ptr, (System.IntPtr)_ttf.Length, (System.IntPtr)0, &face);
                FT.FT_Set_Char_Size(face, (System.IntPtr)0, (System.IntPtr)(fontsize << 6), 300, 300);
                _ft_face = face;


                //从TTF初始化hbfont
                hbblob = HBSharp.hb_blob_create((IntPtr)ptr, (uint)_ttf.Length,
                    HBSharp.hb_memory_mode.HB_MEMORY_MODE_READONLY, System.IntPtr.Zero, System.IntPtr.Zero);



                hbface = HBSharp.hb_face_create(hbblob, 0);


                hbfont = HBSharp.hb_font_create(hbface);
                Debug.LogWarning("==>从TTF 中 初始化HBFont");
                var facecount = HBSharp.hb_face_count(hbblob);
                var glyphcount = HBSharp.hb_face_get_glyph_count(hbface);
                Debug.LogWarning("facecount=" + facecount + " ,glyphcount=" + glyphcount);

               

            }
        }
        var glyphs = String2Glyphs(_text);

        UpdateMesh(packTexture, glyphs);
    }
    unsafe void ClearFont()
    {
        FT.FT_Done_Face(_ft_face);
        _ft_face = null;
    }
    unsafe void Load_Glyph(uint glyph_index)
    {
        var error = FT.FT_Load_Glyph(_ft_face, glyph_index, FT_LOAD.FT_LOAD_DEFAULT);
        error = FT.FT_Render_Glyph(_ft_face->glyph, FT_Render_Mode_.FT_RENDER_MODE_NORMAL);
    }
    unsafe FT_GlyphSlotRec_* GetGlyph()
    {
        return _ft_face->glyph;
    }
    void ClearMesh()
    {
        this.GetComponent<MeshFilter>().mesh = new Mesh();
    }
    unsafe void UpdateMesh(PackTexture packTexture, uint[] glyphs)
    {
        packTexture.ClearGlyph();

        var mesh = this.GetComponent<MeshFilter>().mesh;
        var mat = this.GetComponent<MeshRenderer>().material;
        mat.mainTexture = packTexture.texture;

        mesh_x = 0;
        mesh_pos.Clear();
        mesh_uv.Clear();
        foreach (var g in glyphs)
        {
            if (packTexture.TryGetGlyph(g, out var info))
            {

            }
            else
            {
                Load_Glyph(g);
                info = packTexture.UpdateGlyph(GetGlyph());
                ;
            }
            UpdateMesh_Char(info);
        }
        mesh.vertices = mesh_pos.ToArray();
        mesh.uv = mesh_uv.ToArray();

        int[] tris = new int[mesh.vertices.Length / 4 * 6];
        for (var i = 0; i < mesh.vertices.Length / 4; i++)
        {
            tris[i * 6 + 0] = i * 4 + 0;
            tris[i * 6 + 1] = i * 4 + 1;
            tris[i * 6 + 2] = i * 4 + 2;
            tris[i * 6 + 3] = i * 4 + 2;
            tris[i * 6 + 4] = i * 4 + 1;
            tris[i * 6 + 5] = i * 4 + 3;
        }
        mesh.triangles = tris;

        Color32[] colors = new Color32[mesh.vertices.Length];
        for (var i = 0; i < colors.Length; i++)
        {
            colors[i] = Color.white;
        }
        mesh.colors32 = colors;

        mesh.SetSubMesh(0, new UnityEngine.Rendering.SubMeshDescriptor(0, tris.Length, MeshTopology.Triangles));
        mesh.UploadMeshData(false);
    }
    void UpdateMesh_Char(CharInfo info)
    {
        var mesh = this.GetComponent<MeshFilter>().mesh;
        float scale = 1.0f / 64;
        mesh_pos.Add(new Vector3(scale * (mesh_x + info.border_left),
            scale * (info.border_top), 0));
        mesh_pos.Add(new Vector3(scale * (mesh_x + info.border_left + info.width),
            scale * (info.border_top), 0));
        mesh_pos.Add(new Vector3(scale * (mesh_x + info.border_left),
            scale * (info.border_top - info.height), 0));
        mesh_pos.Add(new Vector3(scale * (mesh_x + info.border_left + info.width),
            scale * (info.border_top - info.height), 0));

        mesh_uv.Add(new Vector3(info.u0, info.v0));
        mesh_uv.Add(new Vector3(info.u1, info.v0));
        mesh_uv.Add(new Vector3(info.u0, info.v1));
        mesh_uv.Add(new Vector3(info.u1, info.v1));



        mesh_x += info.advX;
        //Debug.Log("mesh_x=" + mesh_x);
    }
}
